package com.ck567.netty.chatroom.protocol

import com.ck567.netty.chatroom.config.Config
import com.ck567.netty.chatroom.message.Message
import io.netty.buffer.ByteBuf
import io.netty.channel.ChannelHandler
import io.netty.channel.ChannelHandlerContext
import io.netty.handler.codec.MessageToMessageCodec

@ChannelHandler.Sharable
/**
 * 必须和 LengthFieldBasedFrameDecoder 一起使用，确保接到的 ByteBuf 消息是完整的
 */
class MessageCodecSharable : MessageToMessageCodec<ByteBuf, Message>() {
    override fun encode(ctx: ChannelHandlerContext?, msg: Message?, outList: MutableList<Any>) {
        val out = ctx!!.alloc().buffer()
        // 1. 4 字节的魔数
        out.writeBytes(byteArrayOf(1, 2, 3, 4))
        // 2. 1 字节的版本,
        out.writeByte(1)
        // 3. 1 字节的序列化方式 jdk 0 , json 1
        out.writeByte(Config.getSerializerAlgorithm().ordinal)
        // 4. 1 字节的指令类型
        out.writeByte(msg!!.getMessageType())
        // 5. 4 个字节
        out.writeInt(msg.sequenceId)
        // 无意义，对齐填充
        out.writeByte(0xff)
        // 6. 获取内容的字节数组
        val bytes: ByteArray = Config.getSerializerAlgorithm().serialize(msg)
        // 7. 长度
        out.writeInt(bytes.size)
        // 8. 写入内容
        out.writeBytes(bytes)
        outList.add(out)
    }

    override fun decode(ctx: ChannelHandlerContext?, msg: ByteBuf, out: MutableList<Any>?) {
        val magicNum: Int = msg.readInt()
        val version: Byte = msg.readByte()
        val serializerAlgorithm: Byte = msg.readByte() // 0 或 1

        val messageType: Byte = msg.readByte() // 0,1,2...
        val sequenceId: Int = msg.readInt()
        msg.readByte()
        val length: Int = msg.readInt()
        val bytes = ByteArray(length)
        msg.readBytes(bytes, 0, length)

        // 找到反序列化算法
        val algorithm = Serializer.Algorithm.values()[serializerAlgorithm.toInt()]

        // 确定具体消息类型
        val messageClass: Class<out Message?> = Message.getMessageClass(messageType.toInt() and 0xff)
        val message = algorithm.deserialize(messageClass, bytes)!!
//        log.debug("{}, {}, {}, {}, {}, {}", magicNum, version, serializerType, messageType, sequenceId, length);
//        log.debug("{}", message);
        out!!.add(message)
    }

}